package io.nieyuanhong.wallpaperEngineUnpkg;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

public class Main {
	private packFile packFile;
	private byte[] b4096 = new byte[4096];
	private static final String FORMAT_WARNING = "File format maybe not right!";
	private static final String READ_WRITE_ERROR = "Read write error!";
	private static final String INIT_SUCCESS = "Init success!";
	private static final String UNPACK_SUCCESS = "Unpack success!";
	
	public static void start(String[] args) {
		if (args.length == 0){
			System.out.println("用法:\n"
					+ "\tunpack <pkg文件路径> [<输出路径>]\n"
					+ "例子:\n"
					+ "\tunpack C:\\example.pkg\n"
					+ "\tunpack C:\\example.pkg C:\\output\n"
					//+ "\tunpack D:\\games\\steam\\steamapps\\workshop\\content\\431960\\837681768\\scene.pkg \"D:\\games\\steam\\steamapps\\common\\wallpaper_engine\\projects\\myprojects\\New projects\""
				);
			return;
		}
		Main main = new Main();
		String initMsg = main.init(args[0]);
		System.out.println(initMsg);
		if(INIT_SUCCESS.equals(initMsg)){
			String unpackmsg;
			String parent = new File(args[0]).getParent();
			if (args.length==1)
				unpackmsg = main.unpack(main.packFile, parent,null);
			else unpackmsg = main.unpack(main.packFile, "".equals(args[1].trim()) ? parent : args[1],null);
			System.out.println(unpackmsg);
		}
	}
	
	public static void main(String[] args) {
		start(args);
		//java.awt.Image
		
	}
	
	public String init(String pack)  {
		File file = new File(pack);
		byte[] b4 = new byte[4];
		int readInt = 0;
		try (RandomAccessFile raf = new RandomAccessFile(file, "r")) {
			raf.read(b4);
			if (bytesToInt(b4) != 8)
				System.out.println(FORMAT_WARNING);
			raf.read(b4);
			String fileHead = new String(b4).substring(0, 3);
			raf.read(b4);
			fileHead += new String(b4);
			if (!"PKGV".equals(fileHead))
				System.out.println(FORMAT_WARNING);
			packFile = new packFile();
			packFile.path = pack;
			raf.read(b4);
			packFile.count = bytesToInt(b4);
			//packFile.length = file.length();
			packFile.innerFiles = new InnerFile[packFile.count];
			for (int i = 0; i< packFile.count; i++) {
				packFile.innerFiles[i] = new InnerFile();
				raf.read(b4);
				readInt = bytesToInt(b4);
				raf.read(b4096, 0, readInt);
				packFile.innerFiles[i].fileName = new String(b4096, 0, readInt,"utf8");
				raf.read(b4);
				packFile.innerFiles[i].start = bytesToInt(b4);
				raf.read(b4);
				packFile.innerFiles[i].length = bytesToInt(b4);
			}
			packFile.filesStart = raf.getFilePointer();
		} catch (IOException e) {
			e.printStackTrace();
			return READ_WRITE_ERROR;
		}
		return INIT_SUCCESS;
	}
	
	//reverse bytes To Int
	public int bytesToInt(byte[] b4) {
		return (b4[3] & 0xFF) << 24 |
				(b4[2] & 0xFF) << 16 |
				(b4[1] & 0xFF) << 8 |
				(b4[0] & 0xFF) ;
	}
	
	private void msg(String msg){
		if (msg.equals(READ_WRITE_ERROR))
			throw new RuntimeException();
	}
	
	public String unpack(packFile packFile, String outPath, RandomAccessFile r) {
		//System.out.println(packFile.path+" : "+outPath);
		try(RandomAccessFile raf= r == null ? new RandomAccessFile(new File(packFile.path), "r") : r){
			msg(unpackDo(packFile, outPath, raf));
		}catch (IOException e) {
			e.printStackTrace();
			return READ_WRITE_ERROR;
		}
		return UNPACK_SUCCESS;
	}
	
	public String unpackDo(packFile packFile, String outPath, RandomAccessFile r) throws IOException {
		File fileOut;
		RandomAccessFile raf = r;
		for (InnerFile innerFile : packFile.innerFiles) {
			innerFile.start += packFile.filesStart;
			raf.seek(innerFile.start);
			outPath = outPath.replaceAll("\"", "");
			fileOut = new File(outPath, innerFile.fileName);
			System.out.println(fileOut);
			fileOut.getParentFile().mkdirs();
			fileOut.createNewFile();
			msg(fileIO(fileOut, innerFile, raf));
			raf.seek(innerFile.start);
			if (innerFile.fileName.endsWith(".tex"))
				msg(unpackDo(getTex(raf, packFile.path, innerFile.fileName), outPath, raf));
		}
		return UNPACK_SUCCESS;
	}
	
	private String fileIO(File fileOut,InnerFile innerFile, RandomAccessFile raf) {
		long readBytes = innerFile.length;
		try (RandomAccessFile rafOut = new RandomAccessFile(fileOut, "rw")) {
			do{
				rafOut.write( b4096, 0, raf.read(b4096,0, readBytes > b4096.length ? b4096.length: (int) readBytes));
				readBytes -= b4096.length;
			}while (readBytes > 0);
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException();
		}
		return UNPACK_SUCCESS;
	}
	
	private packFile getTex(RandomAccessFile raf, String path, String fileName) throws IOException {
		long oldSeek = raf.getFilePointer();
		packFile packFile = new packFile();
		packFile.path = path;
		packFile.count = 1;
		packFile.filesStart = oldSeek;
		InnerFile imgFile = new InnerFile();
		raf.seek(oldSeek + 0x32);
		raf.read(b4096, 0, 4);
		String code = new String(b4096,0,4);
		int off = 0;
		if (code.endsWith("1"))
			off=71;
		else if (code.endsWith("2"))
			off=79;
		else if (code.endsWith("3"))
			off=83;
		else return null;
		raf.seek(oldSeek + off);
		raf.read(b4096, 0, 4);
		imgFile.length = bytesToInt(b4096);
		imgFile.start = off + 4;
		imgFile.fileName = fileName.replaceAll(".tex$",".png" );
		packFile.innerFiles = new InnerFile[]{imgFile};
		return packFile;
	}
	
}
